#include "g_shaders.h"

#include <iostream>
#include <string>
#include <fstream>

using namespace std;

//GLuint shaders::font_shader = 0;
GLuint shaders::phong_shader = 0;
GLuint shaders::lambert_shader = 0;

//GLuint shaders::font_texture = 0;

string readShaderFile(const char* file_name)
{
	ifstream iFile;
	iFile.open(file_name, ios::in);

	if (!iFile.good()) cout<<"File I/O Error!\n";

	string code, sLine;
	code = "";
	sLine = "";

	while (!iFile.eof())
	{
		getline(iFile, sLine, '\n');
		code = code + sLine + '\n';
	}

	iFile.close();

	//view the code
	
	//cout<<"Shader code:"<<endl;
	//cout<<code.c_str();
	
	//-------------

	return code;
}

GLuint shaders::createShaderProgram(const char * vsFile, const char * fsFile)
{
	GLuint pHandle;
	GLuint vShader, fShader;

	vShader = glCreateShader(GL_VERTEX_SHADER);
	fShader = glCreateShader(GL_FRAGMENT_SHADER);

	string vShaderSource = readShaderFile(vsFile);
	string fShaderSource = readShaderFile(fsFile);

	const char* t1 = vShaderSource.c_str();
	const char* t2 = fShaderSource.c_str();

	glShaderSource(vShader, 1, &t1, NULL);
	glShaderSource(fShader, 1, &t2, NULL);

	glCompileShader(vShader);
	glCompileShader(fShader);

	int status = 3;
	glGetShaderiv(vShader, GL_COMPILE_STATUS, &status);
	cout<<"Vertex shader compile status: "<<status<<endl;
	
	glGetShaderiv(fShader, GL_COMPILE_STATUS, &status);
	cout<<"Fragment shader compile status: "<<status<<endl;

	int infologLength = 0;
	int maxLength;

	//Analyzing the log

	glGetShaderiv(vShader, GL_INFO_LOG_LENGTH, &maxLength);
	char* infoLog = new char[maxLength];
	glGetShaderInfoLog(vShader, maxLength, &infologLength, infoLog);
	if (infologLength > 0) cout<<"Vertex Shader Log: "<<infoLog<<endl;

	delete[] infoLog;

	glGetShaderiv(fShader, GL_INFO_LOG_LENGTH, &maxLength);
	infoLog = new char[maxLength];
	glGetShaderInfoLog(fShader, maxLength, &infologLength, infoLog);
	if (infologLength > 0) cout<<"Fragment Shader Log: "<<infoLog<<endl;

	delete[] infoLog;
	infoLog = NULL;

	//-------------------
	
	pHandle = glCreateProgram();

	glAttachShader(pHandle, vShader);
	glAttachShader(pHandle, fShader);

	glLinkProgram(pHandle);

	return pHandle;
}

GLuint shaders::createTexture(const char* file_name)
{
	GLuint texHandle;

	glGenTextures(1, &texHandle);
	glBindTexture(GL_TEXTURE_2D, texHandle);

	glfwLoadTexture2D(file_name, GLFW_BUILD_MIPMAPS_BIT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	return texHandle;
}

void shaders::initShaders()
{
	cout<<"----- Initializing shaders -----\n\n";

	//font_shader = createShaderProgram("shaders\\font_vShader.vert", "shaders\\font_fShader.frag");
	phong_shader = createShaderProgram("shaders\\phong_vShader.vert", "shaders\\phong_fShader.frag");
	lambert_shader = createShaderProgram("shaders\\lambert_vShader.vert", "shaders\\lambert_fShader.frag");

	//font_texture = createTexture("textures\\font.tga");

	//link textures to shaders
	GLuint samplerLocation;

	//send textures to the font shader
	/*
	glUseProgram(font_shader);

	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, font_texture);
	samplerLocation = glGetUniformLocation(font_shader, "font_texture");
	glUniform1i(samplerLocation, 0);
	*/

	//link VBO array slots to shaders
	glBindAttribLocation(phong_shader, 0, "pos");
	glBindAttribLocation(phong_shader, 1, "nml");
	glBindAttribLocation(phong_shader, 2, "tex");
	glLinkProgram(phong_shader);

	glBindAttribLocation(lambert_shader, 0, "pos");
	glBindAttribLocation(lambert_shader, 1, "nml");
	glBindAttribLocation(lambert_shader, 2, "tex");
	glLinkProgram(lambert_shader);

	glUseProgram(0);

	cout<<"\n----- Initializing shaders -----\n\n";
}